package versionAscensor;

import gnu.io.*;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.TooManyListenersException;

import javax.swing.Timer;

public class ComunicacionSerie
{

	public ComunicacionSerie() // este es el constructor!
	{
		// super();
	}

	private OutputStream outputStream;
	private SerialPort puertoSerie = null;
	private CommPortIdentifier identificadorDePuerto;
	private InputStream in;
	private SerialPort puertoCerrar;

	// private byte[] readBuffer = new byte[400];
	private int[] BufferLectura = new int[400];
	private int PuertosDetectados = 0; // almaceno los puertos detectados
	public boolean DatosRecibidos = false;
	public boolean Contestacion = false;
	
	public boolean ErrorComunicacion = false;
	
	public int PoscicionAscensor = 0 ;	//Piso en que se encuentra el ascensor.
	public int EstadoAscensor = 0;		//Si esta subiendo o bajando.	
	
	int len = 0;
	int largoborrar = 0;
	
	Timer timerArduino = null;

	/*
	private String AnombreDePuerto = null;
	private String ARatioBaudios = null;
	private String ABitsdatos = null;
	private String ABitsparada = null;
	private String AParidad = null;
	//*/
	
	// Constructores y destructores
	/*
	 * Metodos: QueDevuelve nombreDeFuncion (tipoDeParametro parametro1,
	 * tipoDeParametro parametro2, ...)
	 * 
	 * SerialPort Abrirpuerto( )
	 * 
	 * //
	 * ------------------------------------------------------------------------
	 * ----------------------------------------------------- //
	 */
	/**
	 * 
	 * @param nombreDePuerto
	 * @param RatioBaudios
	 * @param Bitsdatos
	 * @param Bitsparada
	 * @param Paridad
	 * @return
	 * @return
	 * @throws Exception
	 * 
	 *             Parametros a pasar a la funcion, todos del tipo String Puerto
	 *             a abrir : nombreDePuerto BauRate,
	 *             Bitsdatos,Bitsparada,Paridad
	 */
	// public SerialPort Abrirpuerto(String nombreDePuerto, String RatioBaudios,
	// String Bitsdatos, String Bitsparada, String Paridad)
	// throws Exception
	@SuppressWarnings("unused")
	public void Abrirpuerto(String nombreDePuerto, String RatioBaudios,
			String Bitsdatos, String Bitsparada, String Paridad)
			throws Exception
	{
	/*	
		AnombreDePuerto = nombreDePuerto;
		ARatioBaudios = RatioBaudios;
		ABitsdatos = Bitsdatos;
		ABitsparada = Bitsparada;
		AParidad = Paridad;//*/
		/**
		 * Definicion de las variables a utilizar
		 */
		/*
		 * // CommPortIdentifier portId; OutputStream outputStream; //
		 * SerialPort PUERTOCERRAR; SerialPort puertoSerie = null;
		 * CommPortIdentifier identificadorDePuerto; InputStream in; //
		 */
		identificadorDePuerto = CommPortIdentifier
				.getPortIdentifier(nombreDePuerto);

		if (identificadorDePuerto.isCurrentlyOwned()) // Si el puerto ya esta
														// abierto que de Error
		{
			System.out
					.println("Error: El Puerto solicitado ya se encuentra en uso");

		} else
		{

			CommPort commPort = identificadorDePuerto.open("SimpleWrite", 500);//2000);// sino
																				// esta
																				// usado
																				// tratar
																				// de
																				// capturar
																				// y
																				// abrir

			if (commPort instanceof SerialPort)
			{
				puertoSerie = (SerialPort) commPort;

				try
				{
					outputStream = puertoSerie.getOutputStream();
				} catch (IOException e)
				{
					
				}

				puertoSerie.setSerialPortParams(Integer.valueOf(RatioBaudios),
						Integer.valueOf(Bitsdatos),
						Integer.valueOf(Bitsparada), Integer.valueOf(Paridad));

				// InputStream in = serialPort.getInputStream();
				in = puertoSerie.getInputStream();
				OutputStream out = puertoSerie.getOutputStream();// TODO
				// verificar si sirve de algo

				try
				{
					puertoSerie.notifyOnOutputEmpty(true);
				} catch (Exception e)

				{
					System.out
							.println("Error seteando la notificacion del evento");

					System.out.println(e.toString());
					System.exit(-1);
				}

			} else
			{
				System.out
						.println("Error: Only serial ports are handled by this example.");// TODO
																							// traducir
			}
			System.out.println("puerto Abierto " + nombreDePuerto);
		}
		// return puertoSerie;

	}

	// -----------------------------------------------------------------------------------------------------------------------------

	public int[] Analizar()
	{
		@SuppressWarnings("unused")
		int Arduino = (char)BufferLectura[2] - 48; //obtengo el nro de la
		// placa que me envia
		int placa1 = (char) BufferLectura[3] - 48;
		
		int placa2 = (char) BufferLectura[6] - 48;
		
		int placa3 = (char) BufferLectura[9] - 48;
		
		int placa4 = (char) BufferLectura[12] - 48;

		int[] PISO = new int[64];
		int [] Vector1 = new int [20];
				
		Vector1 = DetectarPiso(placa1, BufferLectura[4],BufferLectura[5]);
		for (int pos = 0; pos < 16; ++ pos) PISO[pos] = Vector1[pos];
		Vector1 = DetectarPiso(placa2, BufferLectura[7],BufferLectura[8]);
		for (int pos = 16; pos < 32; ++ pos) PISO[pos] = Vector1[pos-16];
		Vector1 = DetectarPiso(placa3, BufferLectura[10],BufferLectura[11]);
		for (int pos = 32; pos < 48; ++ pos) PISO[pos] = Vector1[pos-32];
		Vector1 = DetectarPiso(placa4, BufferLectura[13],BufferLectura[14]);
		for (int pos = 48; pos < 64; ++ pos) PISO[pos] = Vector1[pos-48];
		EstadoAscensor = BufferLectura[13];
		PoscicionAscensor = BufferLectura[14];
		
		/*
		for (int u=0; u< (BufferLectura[3]-48);++u)
		{
			PISO[u]= BufferLectura[u+4]+48;
			System.out.println(PISO[u]);
		}
		//*/
/*	
		switch (placa)
		{
		case 1:
			piso = 0;
			break;
		case 3:
			piso = 16;
			break;
		case 5:
			piso = 32;
			break;
		case 7:
			piso = 48;
			break;
		}
//*
		// System.out.println("TRATANDO ANALIZAR" + piso);

		for (int u = 0; u < 8; ++u)
		{
			if ((BufferLectura[3] & (1L << u)) == 0) // analizo uno de los
														// "nibbles" recibido
			{
				Seleccion1 = u + 1 + piso;
				PISO[u] = Seleccion1;
				// System.out.println("el piso " + (Seleccion1) +
				// " esta solicitado ");
				// cadenaanterior = ascensor.NewJFrame.jAreaTexto1.getText();
				// ascensor.NewJFrame.jAreaTexto1.setText(cadenaanterior+ "|" +
				// Seleccion1);
				// CadenaMedia1 = String.valueOf(Seleccion1);
			}
		}
		// System.out.println(Cadena[3]);

		for (int u = 0; u < 8; ++u)
		{
			if ((BufferLectura[4] & (1L << u)) == 0)// analizo el otro de los
													// "nibbles" recibido
			{
				Seleccion2 = u + 9 + piso;
				PISO[u + 8] = Seleccion2;
				// System.out.println("el piso " + (Seleccion2) +
				// " esta solicitado ");
				// cadenaanterior = ascensor.NewJFrame.jAreaTexto1.getText();
				// ascensor.NewJFrame.jAreaTexto1.setText(cadenaanterior+ "|" +
				// Seleccion2);
				// CadenaMedia2 = String.valueOf(Seleccion2);
			}
		}//
//*/
		// vacio el buffer de datos recibidos!
		for (int data = 0; data <= largoborrar; ++data)
		{
			BufferLectura[data] = 0;

		}
		// CadenaDevolver = CadenaMedia1 + CadenaMedia2;
		// return CadenaDevolver;
		
		//*/
		return PISO; // Devuelvo en forma de vector los posibles pisos

	}
	
	//-----------------------------------------------------------------------------------------------------------------------------
	public int[] DetectarPiso (int placa, int ByteBajo, int ByteAlto)
	{
		int piso = 0;
		int [] Vectorintermedio = new int[20];
		int Seleccion1 = 0;
		int Seleccion2 = 0;
		switch (placa)
		{
		case 1:
			piso = 0;
			break;
		case 3:
			piso = 16;
			break;
		case 5:
			piso = 32;
			break;
		case 7:
			piso = 48;
			break;
		}
		for (int u = 0; u < 8; ++u)
		{
			if ((ByteBajo & (1L << u)) == 0) // analizo uno de los
														// "nibbles" recibido
			{
				Seleccion1 = u + 1 + piso;
				Vectorintermedio[u] = Seleccion1;
				// System.out.println("el piso " + (Seleccion1) +
				// " esta solicitado ");
				// cadenaanterior = ascensor.NewJFrame.jAreaTexto1.getText();
				// ascensor.NewJFrame.jAreaTexto1.setText(cadenaanterior+ "|" +
				// Seleccion1);
				// CadenaMedia1 = String.valueOf(Seleccion1);
				//if (Vectorintermedio[u] != 0)System.out.println(Vectorintermedio[u]);
			}
		}
		// System.out.println(Cadena[3]);

		for (int u = 0; u < 8; ++u)
		{
			if ((ByteAlto & (1L << u)) == 0)// analizo el otro de los
													// "nibbles" recibido
			{
				Seleccion2 = u + 9 + piso;
				Vectorintermedio[u + 8] = Seleccion2;
				// System.out.println("el piso " + (Seleccion2) +
				// " esta solicitado ");
				// cadenaanterior = ascensor.NewJFrame.jAreaTexto1.getText();
				// ascensor.NewJFrame.jAreaTexto1.setText(cadenaanterior+ "|" +
				// Seleccion2);
				// CadenaMedia2 = String.valueOf(Seleccion2);
				
			}
		}//
		
		return Vectorintermedio;
	}
	
	// -----------------------------------------------------------------------------------------------------------------------------
	/**
	 * 
	 * @param nombreDePuerto
	 * @throws Exception
	 */

	// public void CerrarPuerto(String nombreDePuerto, SerialPort puerto) throws
	// Exception
	public void CerrarPuerto() throws Exception
	{
		/*
		 * OutputStream outputStream; SerialPort puertoCerrar;
		 * CommPortIdentifier identificadorDePuerto; InputStream in;
		 * 
		 * identificadorDePuerto = CommPortIdentifier
		 * .getPortIdentifier(nombreDePuerto); //
		 */
		puertoCerrar = puertoSerie;
		System.out.println("Tratando de cerrar el puerto");

		if (identificadorDePuerto.getPortType() == CommPortIdentifier.PORT_SERIAL)
		{
			System.out.println("Cerrando Puerto "
					+ identificadorDePuerto.getName());
			// puertoCerrar = puerto;
			try
			{
				outputStream = puertoCerrar.getOutputStream();
			} catch (IOException e)
			{
				System.out.println("ERROR");// TODO Traducir
			}
			try
			{
				puertoCerrar.notifyOnOutputEmpty(true);
			} catch (Exception e)
			{
				System.out.println("Error setting event notification");// TODO
																		// Traducir
				System.out.println(e.toString());
				System.exit(-1);
			}
			try
			{
				/**
				 * TODO 
				 * VER SI SE PUEDE DEJAR LA DEMORA 
				 * EN EL MENOR VALOR POSIBLE
				 * */
				//Thread.sleep(2000); // Be sure data is xferred before closing
				Thread.sleep(1000); // Be sure data is xferred before closing
			} catch (Exception e)
			{
			}

			puertoCerrar.close();// */
			System.out.println("Puerto Cerrado " + identificadorDePuerto.getName());
			// System.exit(1);

		}

	}

	// -----------------------------------------------------------------------------------------------------------------------------
	private void readSerial()
	{
		len = 0;
		int data = 0;
		PuertosDetectados = 0;
		try
		{
			int availableBytes = in.available();

			if (availableBytes > 0)
			{

				while ((data = in.read()) > 1)
				{
					/**
					 * Leo datos en el buffer hasta que llegue el final de linea
					 */
					if (data == '\n' || data == '#')
					{
						break;
					}
					BufferLectura[len++] = data;
					//System.out.println(data);
				}
				/**
				 * si llegan datos de lectura del puerto
				 */
				largoborrar = len;

				if (BufferLectura[0] == '*') // si se encontro un inicio
												// de trama
				{
					/**
					 * R equivale a una lectura de EE de u y esta devolviendo la
					 * direccion del mismo
					 */
					if (BufferLectura[1] == 'R')
					{
						PuertosDetectados = BufferLectura[2] - 48; // aca tengo
																	// el
																	// valor
																	// recibido
																	// de
																	// la
																	// contestacion
																	// del
																	// Arduino

					}// */

					/**
					 * L es la correspondiente lectura de los puertos
					 */
					if (BufferLectura[1] == 'L') // si el primer valor recibido
													// indica que es una lectura
													// de
													// puerto
					{
						// System.out.println("LLEGO DATO");
						largoborrar = len;
						Contestacion = false;
						DatosRecibidos = true;

					}// */
					/**
					 * P es la confirmacion de la ejecucion de una salida, que
					 * envia el u
					 */
					if (BufferLectura[1] == 'P')
					{
						DatosRecibidos = false;
						Contestacion = true;
						/*
						 * System.out.println("Ard " + (BufferLectura[1]-48));
						 * System.out.println("Sal " + (BufferLectura[2]-48));
						 * System.out.println("otro " +
						 * (BufferLectura[3]-48));//
						 */
						/*
						@SuppressWarnings("unused")
						int Asacar = 0;
						if ((BufferLectura[3] - 48) >= 0
								&& (BufferLectura[3] - 48) < 100)
							Asacar = (BufferLectura[2] - 48) * 10
									+ ((BufferLectura[3] - 48));
						else if ((BufferLectura[3] - 48) < 0
								|| (BufferLectura[3] - 48) > 100)
							Asacar = (BufferLectura[2] - 48);
						//*/
						/**
					 * 
					 * 
					 */
						// System.out.println("sacar " + Asacar);
						// System.out.println(BufferLectura[2] + " " +
						// BufferLectura[3]);

						for (int u = 0; u <= largoborrar; ++u) // vacio el dato
																// recibido para
																// que
																// no me
																// interfiera
																// con lo demas
						{

							BufferLectura[u] = 0;
						}
						largoborrar = 0;
						len = 0;// */
						// System.out.println("Ard" + BufferLectura[1]);

					}// */
				}
			}
		} catch (IOException e)
		{
		}
	}

	// -------------------------------------------------------------------------------------------------------------------------------
	/**
	 * 
	 * @return
	 * getter de La direccion detectada.
	 */
	public int getDireccionDetectada()
	{
		int temporal = PuertosDetectados;
		PuertosDetectados = 0;
		return temporal;
	}

	/**
	 * 
	 * @author laboratorio Esto es para implementar como un THREAD
	 */
	/*
	 * 
	 * private class ReadThread implements Runnable { public void run() { while
	 * (true) { readSerial(); } } }
	 * 
	 * public void setSerialListener() { new Thread(new ReadThread()).start(); }
	 * //
	 */

	/**
	 * Esto es para implementar como un evento
	 * 
	 */

	private class SerialEventHandler implements SerialPortEventListener
	{
		public void serialEvent(SerialPortEvent event)
		{
			switch (event.getEventType())
			{
			case SerialPortEvent.DATA_AVAILABLE:
				readSerial();
				break;
			}
		}
	}

	/**
	 * Set the serial event handler
	 */
	private void setSerialEventHandler(SerialPort serialPort1)
	{
		try
		{
			// Add the serial port event listener
			serialPort1.addEventListener(new SerialEventHandler());
			serialPort1.notifyOnDataAvailable(true);
		} catch (TooManyListenersException ex)
		{
			System.err.println(ex.getMessage());
		}
	}

	// -----------------------------------------------------------------------------------------------------------------------------
	/**
	 * Funcion que escribe una cadena en el puerto
	 * 
	 * 
	 */
	public void EscribirPuerto(String messageString)
	{
		messageString = "*" + messageString + "#"; // el * es inicio y el # es
													// el fin de cadena
		// System.out.println("valor escrito" + messageString);
		try
		{
			outputStream.write(messageString.getBytes());
		} catch (IOException e)
		{
			System.out.println("Error Al enviar dato " +  identificadorDePuerto.getName());
			ErrorComunicacion = true;
		}
		try
		{
			outputStream.flush();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	// -----------------------------------------------------------------------------------------------------------------------------
	/**
	 * Funcion para la lectura del puerto!
	 * 
	 * @return
	 */
/*	
	public void LeerPuerto(int Puerto)
	{
		this.EscribirPuerto("OPX" + Puerto);
		// readSerial();
	}
//*/
	/**
	 * Actualizacion del protocolo. Solo envio un unico dato para que me
	 * responda! El estado de todos los puertos y que pisos han sido
	 * Seleccionados
	 */
	public void LeerPuerto()
	{
		this.EscribirPuerto("OPXX");
	}
//-----------------------------------------------------------------------------------------------------------------------------------------
//Timer para error en caso de que el arduino no responda.
	/**
	 * Inicia el timer de Lectura de estado de los arduinos
	 */
	public void IniciarTimerArduino()
	{
		timerArduino.start();
	}

	/**
	 * Detiene el timer de Lectura detener el timer de los arduinos
	 */
	public void DetenerTimerArduino()
	{
		timerArduino.stop();
	}
	
	/**
	 * Reiniciar el timer
	 */
	public void ReiniciarTimerArduino()
	{
		timerArduino.restart();
	}
	
	/**
	 * Timer de Error.
	 * Se habilita este timer cada vez que se quiere esperar una respuesta
	 * del Arduino correspondiente.
	 * En caso de que no se reciba la respuesta, se 
	 * Realiza un error, que dispara una reconeccion.
	 */
	public void TemporizadorArduino()
	{
			
		ActionListener AccionArduino = new ActionListener()
		{
			
			/*
			 * El timer se emplea como un evento A continuacion se coloca el
			 * codigo a ser Realizado cada vez que se acciona el timer
			 */
			public void actionPerformed(ActionEvent e)
			{
			System.out.println("Error de respuesta Arduino " +  identificadorDePuerto.getName());	
			ErrorComunicacion = true;
			timerArduino.stop();
			}
			
			

		};// */

		timerArduino = new Timer(2000, AccionArduino); // Seteo de los valores del timer
		timerArduino.stop();
	}

	
	
	// -----------------------------------------------------------------------------------------------------------------------------
	public void main()
	{
		this.setSerialEventHandler(puertoSerie);
	}

}
